\subsection{Пример \#2: SCO OpenServer}

\label{examples_SCO}
\myindex{SCO OpenServer}
Древняя программа для SCO OpenServer от 1997 
разработанная давно исчезнувшей компанией.

Специальный драйвер донглы инсталлируется в системе, он содержит такие текстовые строки:
\q{Copyright 1989, Rainbow Technologies, Inc., Irvine, CA} и \q{Sentinel Integrated Driver Ver. 3.0 }.

После инсталляции драйвера, в /dev появляются такие устройства:

\begin{lstlisting}
/dev/rbsl8
/dev/rbsl9
/dev/rbsl10
\end{lstlisting}

Без подключенной донглы, программа сообщает об ошибке, но сообщение об ошибке не удается
найти в исполняемых файлах.

\myindex{COFF}
Еще раз спасибо \ac{IDA}, она легко загружает исполняемые файлы формата COFF использующиеся в SCO OpenServer.

Попробуем также поискать строку \q{rbsl}, и действительно, её можно найти в таком фрагменте кода:

\lstinputlisting[style=customasmx86]{examples/dongles/2/1.lst}

Действительно, должна же как-то программа обмениваться информацией с драйвером.

\myindex{thunk-функции}
Единственное место где вызывается функция \TT{SSQC()}
это \gls{thunk function}:

\lstinputlisting[style=customasmx86]{examples/dongles/2/2.lst}

А вот SSQ() может вызываться по крайней мере из двух разных функций.

Одна из них:

\lstinputlisting[style=customasmx86]{examples/dongles/2/check1.lst}

\q{\TT{3C}} и \q{\TT{3E}} --- это звучит знакомо: когда-то была донгла
 Sentinel Pro от Rainbow без памяти,
предоставляющая только одну секретную крипто-хеширующую функцию.

О том, что такое хэш-функция, было описано здесь: \myref{hash_func}.

Но вернемся к нашей программе.
Так что программа может только проверить подключена ли донгла или нет.
Никакой больше информации в такую донглу без памяти записать нельзя.
Двухсимвольные коды --- это команды
(можно увидеть, как они обрабатываются в функции 
\TT{SSQC()}) 
а все остальные строки хешируются внутри донглы превращаясь в 16-битное число.
Алгоритм был секретный, так что нельзя было написать замену драйверу или сделать
электронную копию донглы идеально эмулирующую алгоритм.
С другой стороны, всегда можно было перехватить все обращения к ней и найти те константы, с которыми
сравнивается результат хеширования.
Но надо сказать, вполне возможно создать устойчивую защиту от копирования базирующуюся
на секретной хеш-функции: пусть она шифрует все файлы с которыми ваша программа работает.

Но вернемся к нашему коду.

Коды 51/52/53 используются для выбора номера принтеровского LPT-порта.
3x/4x используются для выбора \q{family} так донглы Sentinel Pro
можно отличать друг от друга: ведь более одной донглы может быть подключено к LPT-порту.

Единственная строка, передающаяся в хеш-функцию это\\
 "0123456789".
Затем результат сравнивается с несколькими правильными значениями.

Если результат правилен, 0xC или 0xB будет записано в глобальную переменную \TT{ctl\_model}.

Еще одна строка для хеширования:
"PRESS ANY KEY TO CONTINUE: ", но результат не проверяется.
Трудно сказать, зачем это, может быть по ошибке
\footnote{Это очень странное чувство: находить ошибки в столь древнем ПО.}.

Давайте посмотрим, где проверяется значение глобальной переменной \TT{ctl\_mode}.

Одно из таких мест:

\lstinputlisting[style=customasmx86]{examples/dongles/2/4.lst}

Если оно 0, шифрованное сообщение об ошибке будет передано в функцию дешифрования, и оно будет 
показано.

\myindex{x86!\Instructions!XOR}
Функция дешифровки сообщений об ошибке похоже применяет простой \gls{xoring}:

\lstinputlisting[style=customasmx86]{examples/dongles/2/err_warn.lst}

Вот почему не получилось найти сообщение об ошибке в исполняемых файлах, потому что оно было
зашифровано, это очень популярная практика.

Еще один вызов хеширующей функции передает строку
\q{offln} и сравнивает результат с константами
\TT{0xFE81} и \TT{0x12A9}.
Если результат не сходится, происходит работа с какой-то функцией \TT{timer()} 
(может быть для ожидания плохо подключенной донглы и нового запроса?), затем дешифрует
еще одно сообщение об ошибке и выводит его.

\lstinputlisting[style=customasmx86]{examples/dongles/2/check2.lst}

Заставить работать программу без донглы довольно просто: просто пропатчить все места после инструкций
\CMP где происходят соответствующие сравнения.

Еще одна возможность --- это написать свой драйвер для SCO OpenServer, содержащий таблицу возможных вопросов и ответов, все те что имеются в программе.

\subsubsection{Дешифровка сообщений об ошибке}

Кстати, мы также можем дешифровать все сообщения об ошибке.
Алгоритм, находящийся в функции \TT{err\_warn()} 
действительно, крайне прост:

\lstinputlisting[caption=Функция дешифровки,style=customasmx86]{examples/dongles/2/decrypting_RU.lst}

Как видно, не только сама строка поступает на вход, но также и ключ для дешифровки:

\begin{lstlisting}
.text:0000DAF7 error:                                  ; CODE XREF: sync_sys+255j
.text:0000DAF7                                         ; sync_sys+274j ...
.text:0000DAF7                 mov     [ebp+var_8], offset encrypted_error_message2
.text:0000DAFE                 mov     [ebp+var_C], 17h ; decrypting key
.text:0000DB05                 jmp     decrypt_end_print_message

...

; this name we gave to label manually:
.text:0000D9B6 decrypt_end_print_message:              ; CODE XREF: sync_sys+29Dj
.text:0000D9B6                                         ; sync_sys+2ABj
.text:0000D9B6                 mov     eax, [ebp+var_18]
.text:0000D9B9                 test    eax, eax
.text:0000D9BB                 jnz     short loc_D9FB
.text:0000D9BD                 mov     edx, [ebp+var_C] ; key
.text:0000D9C0                 mov     ecx, [ebp+var_8] ; string
.text:0000D9C3                 push    edx
.text:0000D9C4                 push    20h
.text:0000D9C6                 push    ecx
.text:0000D9C7                 push    18h
.text:0000D9C9                 call    err_warn
\end{lstlisting}

Алгоритм это очень простой \gls{xoring}: 
каждый байт XOR-ится с ключом, но ключ увеличивается на 3 после обработки каждого байта.

Напишем небольшой скрипт на Python для проверки наших догадок:

\lstinputlisting[caption=Python 3.x]{examples/dongles/2/decr1.py}

И он выводит: \q{check security device connection}.
Так что да, это дешифрованное сообщение.

Здесь есть также и другие сообщения, с соответствующими ключами.
Но надо сказать, их можно дешифровать и без ключей.
В начале, мы можем заметить, что ключ --- это просто байт.
Это потому что самая важная часть функции дешифровки
(\XOR) оперирует байтами. 
Ключ находится в регистре \ESI, но только младшие 8 бит
(т.е. байт) регистра используются.
Следовательно, ключ может быть больше 255, 
но его значение будет округляться.

И как следствие, мы можем попробовать обычный перебор всех ключей в диапазоне 0..255.
Мы также можем пропускать сообщения содержащие непечатные символы.

\lstinputlisting[caption=Python 3.x]{examples/dongles/2/decr2.py}

И мы получим:

\lstinputlisting[caption=Results]{examples/dongles/2/decr2_result.txt}

Тут есть какой-то мусор, но мы можем быстро отыскать сообщения на английском языке!

Кстати, так как алгоритм использует простой \XOR, та же функция может использоваться и для шифрования
сообщения.
Если нужно, мы можем зашифровать наши собственные сообщения, и пропатчить программу вставив их.

